// ======================================================================
// Hell Logic Sniffer USB FW
// 
// Copyright 2012-2013 Hell-Prototypes
//
// http://code.google.com/p/hell-prototypes/
//
// This is free software, licensed under the terms of the GNU General
// Public License as published by the Free Software Foundation.
// ======================================================================

#include "..\inc\fx2.h"
#include "..\inc\fx2regs.h"
#include "..\inc\syncdly.h"
#include "..\inc\i2c.h"

void i2c_hw_init()
{
    INT_DISABLE();

    I2CTL = 0;//100K, No interrupt
}

BOOL wait_done(void)
{
    WORD time_out = 0;

    while (!DONE_CHK()) {
        if(ERROR_CHK()) {
            return FALSE;
        }

        if (time_out++ > TIME_OUT) {
            return FALSE;
        }
    }

    return TRUE;
}

BOOL wait_stop(void)
{
    WORD time_out=0;

    while(STOP_CHK()){
		if (time_out++ > TIME_OUT) {
	        return FALSE;
		}
    }

    return TRUE;
}

BOOL i2c_send_byte(BYTE byte)
{
    WORD time_out = 0;

    DATA_WR(byte);
    if(!wait_done()) {
    	return FALSE;
    }

    while (!ACK_CHK()) {
        if(ERROR_CHK()) {
        	return FALSE;
        }
        if (time_out++ > TIME_OUT) {
            return FALSE;
        }
    }

    return TRUE;
}

BOOL i2c_wr_ctrl_byte(BYTE ctrl)
{
    CTRL_START();

    return i2c_send_byte(ctrl);
}

/*
BOOL i2c_wr_bytes(BYTE *buffer, BYTE len)
{
    for (; len >0; len--) {
        if (!i2c_send_byte(*buffer)) {
            CTRL_STOP();
            wait_stop();
            return FALSE;
        }
        buffer++;
    }
}
*/

BOOL i2c_read_bytes(BYTE *buffer, BYTE len)
{
    if(len == 1) {
    	CTRL_LASTRD();
    }

    *buffer = DATA_RD();
    if(!wait_done()) {
        goto ERR_RET;
    }

    if(len > 1) {
        for(; len > 2; len--) {
            *buffer = DATA_RD();
            if(!wait_done()) {
                goto ERR_RET;
            }
            buffer++;
        }

        CTRL_LASTRD();
        *buffer = DATA_RD();

        if(!wait_done()) {
            goto ERR_RET;
        }
        buffer++;
    }

    CTRL_STOP(); 
    *buffer = DATA_RD();

    return wait_stop();

ERR_RET:
    CTRL_STOP();
    wait_stop();
    return FALSE;
}

BOOL at24c64_write_bytes_at(BYTE dev_addr, WORD start_addr, BYTE *buffer, BYTE len)
{
	WORD time_out, addr = start_addr;

	dev_addr &= 0xFE;

	while(len--) {
		if(! i2c_wr_ctrl_byte(dev_addr) ) {
			CTRL_STOP();
            wait_stop();
			return FALSE;
		}

		if (!i2c_send_byte((BYTE)(addr>>8))) {
            CTRL_STOP();
            wait_stop();
            return FALSE;
        }
		if (!i2c_send_byte((BYTE)addr)) {
            CTRL_STOP();
            wait_stop();
            return FALSE;
        }
		addr++;
		if (!i2c_send_byte(*buffer)) {
            CTRL_STOP();
            wait_stop();
            return FALSE;
        }
        buffer++;

		CTRL_STOP();
	    if(! wait_stop() ) {
			return FALSE;
		}

		//ACKNOWLEDGE POLLING
		for(time_out=0; time_out<3000; time_out++) {
			CTRL_START();
			DATA_WR(dev_addr);
    		wait_done();
    		if (ACK_CHK()) {
				break;
			}
		}

		CTRL_STOP();
	    wait_stop();
	}
	return TRUE;
}

BOOL at24c64_read_bytes_at(BYTE dev_addr, WORD start_addr, BYTE *buffer, BYTE len)
{
	BYTE addr_h, addr_l;

	addr_h = (BYTE)(start_addr>>8);
	addr_l = (BYTE)start_addr;

	dev_addr &= 0xFE;

	if(! i2c_wr_ctrl_byte(dev_addr) ) {
		CTRL_STOP();
        wait_stop();
		return FALSE;
	}

	if (!i2c_send_byte(addr_h)) {
        CTRL_STOP();
        wait_stop();
        return FALSE;
    }
	if (!i2c_send_byte(addr_l)) {
        CTRL_STOP();
        wait_stop();
        return FALSE;
    }

	CTRL_START();

	dev_addr |= 0x01;
	if(! i2c_wr_ctrl_byte(dev_addr) ) {
		CTRL_STOP();
        wait_stop();
		return FALSE;
	}

	return i2c_read_bytes(buffer, len);
}

